import torch.nn as nn
import torchvision.transforms as transforms
from torch.utils.data import DataLoader, Dataset
from torch.autograd import Variable
from torch import optim
# import redataset as ds
import redata_pre as ds
import lossDANet as losses
from configDANet import Config as cfg
import os
import numpy as np
from MTCAFNetDANet import BaseNet
import torch.optim
from sklearn.metrics import roc_auc_score
import warnings

# print(torch.version.cuda)

warnings.filterwarnings('ignore')
os.environ["CUDA_VISIBLE_DEVICES"] = cfg.gpu_device


def print_and_write(write_str):
    print(write_str)
    f1 = open(cfg.save_file, 'a+')
    f1.write("\n")
    f1.write(write_str)
    f1.close()


def test_model(datasets):
    output_task_0 = []
    label_task_0 = []
    pred_task_0 = []
    output_task_1 = []
    label_task_1 = []
    pred_task_1 = []
    output_task_2 = []
    label_task_2 = []
    pred_task_2 = []
    output_task_3 = []
    label_task_3 = []
    pred_task_3 = []
    output_task_4 = []
    label_task_4 = []
    pred_task_4 = []
    output_task_5 = []
    label_task_5 = []
    pred_task_5 = []
    output_task_6 = []
    label_task_6 = []
    pred_task_6 = []
    output_task_7 = []
    label_task_7 = []
    pred_task_7 = []

    combine_output_task_0 = []
    combine_label_task_0 = []
    combine_pred_task_0 = []
    combine_output_task_1 = []
    combine_label_task_1 = []
    combine_pred_task_1 = []
    combine_output_task_2 = []
    combine_label_task_2 = []
    combine_pred_task_2 = []
    combine_output_task_3 = []
    combine_label_task_3 = []
    combine_pred_task_3 = []
    combine_output_task_4 = []
    combine_label_task_4 = []
    combine_pred_task_4 = []
    combine_output_task_5 = []
    combine_label_task_5 = []
    combine_pred_task_5 = []
    combine_output_task_6 = []
    combine_label_task_6 = []
    combine_pred_task_6 = []
    combine_output_task_7 = []
    combine_label_task_7 = []
    combine_pred_task_7 = []

    correct = [0, 0, 0, 0, 0, 0, 0, 0]
    correct_combine = [0, 0, 0, 0, 0, 0, 0, 0]

    my_data_loader = DataLoader(datasets, shuffle=False, num_workers=cfg.num_workers, batch_size=cfg.test_batch_size)

    for _, data in enumerate(my_data_loader, 0):

        net.eval()
        img0, img1, label = data
        img0 = Variable(img0).cuda()
        img1 = Variable(img1).cuda()
        for i in range(0, len(label)):
            label[i] = Variable(torch.LongTensor(label[i])).cuda()
        output_x, output_y, output_h, output_f = net(img0, img1)
        for i in range(0, 8):
            predict_prob = output_f[i].data.cpu()
            label_gt = label[i].data.cpu()
            pred = torch.max(predict_prob, 1)[1]
            correct[i] += (pred == label_gt).sum()
            if i == 0:
                output_task_0 += predict_prob
                label_task_0 += label_gt
                pred_task_0 += pred
            elif i == 1:
                output_task_1 += predict_prob
                label_task_1 += label_gt
                pred_task_1 += pred
            elif i == 2:
                output_task_2 += predict_prob
                label_task_2 += label_gt
                pred_task_2 += pred
            elif i == 3:
                output_task_3 += predict_prob
                label_task_3 += label_gt
                pred_task_3 += pred
            elif i == 4:
                output_task_4 += predict_prob
                label_task_4 += label_gt
                pred_task_4 += pred
            elif i == 5:
                output_task_5 += predict_prob
                label_task_5 += label_gt
                pred_task_5 += pred
            elif i == 6:
                output_task_6 += predict_prob
                label_task_6 += label_gt
                pred_task_6 += pred
            elif i == 7:
                output_task_7 += predict_prob
                label_task_7 += label_gt
                pred_task_7 += pred
        for i in range(0, 8):
            # predict_prob = (output_y[i] + output_h[i] + output_f[i]).data.cpu()
            predict_prob = output_f[i].data.cpu()
            label_gt = label[i].data.cpu()
            pred = torch.max(predict_prob, 1)[1]
            correct_combine[i] += (pred == label_gt).sum()
            if i == 0:
                combine_output_task_0 += predict_prob
                combine_label_task_0 += label_gt
                combine_pred_task_0 += pred
            elif i == 1:
                combine_output_task_1 += predict_prob
                combine_label_task_1 += label_gt
                combine_pred_task_1 += pred
            elif i == 2:
                combine_output_task_2 += predict_prob
                combine_label_task_2 += label_gt
                combine_pred_task_2 += pred
            elif i == 3:
                combine_output_task_3 += predict_prob
                combine_label_task_3 += label_gt
                combine_pred_task_3 += pred
            elif i == 4:
                combine_output_task_4 += predict_prob
                combine_label_task_4 += label_gt
                combine_pred_task_4 += pred
            elif i == 5:
                combine_output_task_5 += predict_prob
                combine_label_task_5 += label_gt
                combine_pred_task_5 += pred
            elif i == 6:
                combine_output_task_6 += predict_prob
                combine_label_task_6 += label_gt
                combine_pred_task_6 += pred
            elif i == 7:
                combine_output_task_7 += predict_prob
                combine_label_task_7 += label_gt
                combine_pred_task_7 += pred

    length = len(datasets)
    sum = 0
    sum_combine = 0
    avg_acc_list = []
    avg_combine_acc_list = []
    for i in range(0, 8):
        avg_acc_list.append(int(correct[i]) / length)
        avg_combine_acc_list.append(int(correct_combine[i]) / length)
        print_and_write(task[i] + '      acc:{:.6f}' . format(int(correct[i]) / length))
        print_and_write(task[i] + '      combine acc:{:.6f}'. format(int(correct_combine[i]) / length))
        sum += correct[i]
        sum_combine += correct_combine[i]

    avg_acc = int(sum) / (8 * length)
    avg_combine_acc = int(sum_combine) / (8 * length)
    print_and_write('avg acc:{:.6f}'.format(avg_acc))
    print_and_write('avg combine acc:{:.6f}'.format(avg_combine_acc))

    acc_0, sen_0, spe_0, pre_0, auc_0 = calcACCSenSpePreAUC(output_task_0, pred_task_0, label_task_0, 0)
    acc_1, sen_1, spe_1, pre_1, auc_1 = calcACCSenSpePreAUC(output_task_1, pred_task_1, label_task_1, 1)
    acc_2, sen_2, spe_2, pre_2, auc_2 = calcACCSenSpePreAUC(output_task_2, pred_task_2, label_task_2, 2)
    acc_3, sen_3, spe_3, pre_3, auc_3 = calcACCSenSpePreAUC(output_task_3, pred_task_3, label_task_3, 3)
    acc_4, sen_4, spe_4, pre_4, auc_4 = calcACCSenSpePreAUC(output_task_4, pred_task_4, label_task_4, 4)
    acc_5, sen_5, spe_5, pre_5, auc_5 = calcACCSenSpePreAUC(output_task_5, pred_task_5, label_task_5, 5)
    acc_6, sen_6, spe_6, pre_6, auc_6 = calcACCSenSpePreAUC(output_task_6, pred_task_6, label_task_6, 6)
    acc_7, sen_7, spe_7, pre_7, auc_7 = calcACCSenSpePreAUC(output_task_7, pred_task_7, label_task_7, 7)

    acc = [acc_0, acc_1, acc_2, acc_3, acc_4, acc_5, acc_6, acc_7]
    # acc.append(np.mean(acc))
    sen = [sen_0, sen_1, sen_2, sen_3, sen_4, sen_5, sen_6, sen_7]
    # sen.append(np.mean(sen))
    spe = [spe_0, spe_1, spe_2, spe_3, spe_4, spe_5, spe_6, spe_7]
    # spe.append(np.mean(spe))
    pre = [pre_0, pre_1, pre_2, pre_3, pre_4, pre_5, pre_6, pre_7]
    # pre.append(np.mean(pre))
    auc = [auc_0, auc_1, auc_2, auc_3, auc_4, auc_5, auc_6, auc_7]
    # auc.append(np.mean(auc))

    combine_acc_0, combine_sen_0, combine_spe_0, combine_pre_0, combine_auc_0 = calcACCSenSpePreAUC(combine_output_task_0, combine_pred_task_0, combine_label_task_0, 0)
    combine_acc_1, combine_sen_1, combine_spe_1, combine_pre_1, combine_auc_1 = calcACCSenSpePreAUC(combine_output_task_1, combine_pred_task_1, combine_label_task_1, 1)
    combine_acc_2, combine_sen_2, combine_spe_2, combine_pre_2, combine_auc_2 = calcACCSenSpePreAUC(combine_output_task_2, combine_pred_task_2, combine_label_task_2, 2)
    combine_acc_3, combine_sen_3, combine_spe_3, combine_pre_3, combine_auc_3 = calcACCSenSpePreAUC(combine_output_task_3, combine_pred_task_3, combine_label_task_3, 3)
    combine_acc_4, combine_sen_4, combine_spe_4, combine_pre_4, combine_auc_4 = calcACCSenSpePreAUC(combine_output_task_4, combine_pred_task_4, combine_label_task_4, 4)
    combine_acc_5, combine_sen_5, combine_spe_5, combine_pre_5, combine_auc_5 = calcACCSenSpePreAUC(combine_output_task_5, combine_pred_task_5, combine_label_task_5, 5)
    combine_acc_6, combine_sen_6, combine_spe_6, combine_pre_6, combine_auc_6 = calcACCSenSpePreAUC(combine_output_task_6, combine_pred_task_6, combine_label_task_6, 6)
    combine_acc_7, combine_sen_7, combine_spe_7, combine_pre_7, combine_auc_7 = calcACCSenSpePreAUC(combine_output_task_7, combine_pred_task_7, combine_label_task_7, 7)

    combine_acc = [combine_acc_0, combine_acc_1, combine_acc_2, combine_acc_3, combine_acc_4, combine_acc_5, combine_acc_6, combine_acc_7]
    # combine_acc.append(np.mean(combine_acc))
    combine_sen = [combine_sen_0, combine_sen_1, combine_sen_2, combine_sen_3, combine_sen_4, combine_sen_5, combine_sen_6, combine_sen_7]
    # combine_sen.append(np.mean(combine_sen))
    combine_spe = [combine_spe_0, combine_spe_1, combine_spe_2, combine_spe_3, combine_spe_4, combine_spe_5, combine_spe_6, combine_spe_7]
    # combine_spe.append(np.mean(combine_spe))
    combine_pre = [combine_pre_0, combine_pre_1, combine_pre_2, combine_pre_3, combine_pre_4, combine_pre_5, combine_pre_6, combine_pre_7]
    # combine_pre.append(np.mean(combine_pre))
    combine_auc = [combine_auc_0, combine_auc_1, combine_auc_2, combine_auc_3, combine_auc_4, combine_auc_5, combine_auc_6, combine_auc_7]
    # combine_auc.append(np.mean(combine_auc))

    return avg_acc, avg_combine_acc, avg_acc_list, avg_combine_acc_list, \
           acc, sen, spe, pre, auc, combine_acc, combine_sen, combine_spe, combine_pre, combine_auc


def calcACCSenSpePreAUC(scores, predict, labels, task_id):
    class_list = [3, 3, 3, 2, 3, 2, 3, 5]
    class_num = class_list[task_id]
    acc = []
    sen = []
    spe = []
    pre = []
    auc = []

    for positive_index in range(class_num):
        tp = 0
        fp = 0
        fn = 0
        tn = 0
        new_labels = []
        new_scores = []

        for var in scores:
            # print(type(var), var)
            var = var.data.cpu()
            var = var.numpy().tolist()
            # print(type(var), var)
            z = np.array(var)
            prob = np.exp(z) / sum(np.exp(z))
            new_scores.append(prob[positive_index])
        for each_label in labels:
            if each_label != positive_index:
                new_labels.append(0)
            else:
                new_labels.append(1)

        for k in range(len(labels)):
            if labels[k] == positive_index and predict[k] == positive_index:
                tp += 1
            if labels[k] != positive_index and predict[k] == positive_index:
                fp += 1
            if labels[k] == positive_index and predict[k] != positive_index:
                fn += 1
            if labels[k] != positive_index and predict[k] != positive_index:
                tn += 1

        if (tp + tn + fp + fn) != 0:
            acc.append(int(tp+tn) / (tp + tn + fp + fn))
        else:
            acc.append(0.0)
        if (tp + fn) != 0:
            sen.append(int(tp) / (tp + fn))
        else:
            sen.append(0.0)
        if (tn + fp) != 0:
            spe.append(int(tn) / (tn + fp))
        else:
            spe.append(0.0)
        if (tp + fp) != 0:
            pre.append(int(tp) / (tp + fp))
        else:
            pre.append(0.0)
        # print(new_labels, labels)
        auc.append(roc_auc_score(new_labels, new_scores))
    return acc, sen, spe, pre, auc


def adjust_learning_rate(optimizer, epoch):
    """
    Sets the learning rate to the initial LR decayed by 10 every 30 epochs(step = 30)
    """
    # lr = cfg.warmup_learning_rate
    # if epoch > 10:
    #     lr = cfg.initial_learning_rate / (2 ** (epoch // 50))
    lr = cfg.initial_learning_rate / (2 ** (epoch // 50))
    for i, param_group in enumerate(optimizer.param_groups):
        param_group['lr'] = lr
    return lr


data_transforms = {
    'train': transforms.Compose([
        # transforms.RandomHorizontalFlip(),
        # transforms.Resize(cfg.img_size),
        # transforms.RandomRotation(40),
        # transforms.RandomVerticalFlip(),
        transforms.Resize(cfg.img_size),
        # transforms.RandomCrop(cfg.img_size),
        transforms.RandomRotation(40),
        transforms.RandomHorizontalFlip(),
        transforms.RandomVerticalFlip(),
        transforms.ToTensor(),
        # transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010))]),
        transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]),
    'val': transforms.Compose([
        transforms.Resize(cfg.img_size),
        transforms.ToTensor(),
        transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]),
    'test': transforms.Compose([
        transforms.Resize(cfg.img_size),
        transforms.ToTensor(),
        transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]),
}

image_datasets = {'train': ds.Dataset(cfg.data_train, data_transforms['train']),
                  'train_test': ds.Dataset(cfg.data_train, data_transforms['val']),
                  'val': ds.Dataset(cfg.data_val, data_transforms['val']),
                  'test': ds.Dataset(cfg.data_test, data_transforms['test'])}

train_loader = DataLoader(image_datasets["train"], shuffle=True, num_workers=cfg.num_workers,
                          batch_size=cfg.train_batch_size)

net = BaseNet().cuda()
net = torch.nn.DataParallel(net)
print_and_write(cfg.this_time_log)

criterion = losses.ContrastiveLoss()
# optimizer = optim.SGD(net.parameters(),lr = 0.01, weight_decay= 0.0001, momentum=0.9 )
# optimizer = optim.Adam(net.parameters(),lr = 0.001, weight_decay= 0.01)
optimizer = optim.SGD(net.parameters(), lr=cfg.initial_learning_rate,
                      momentum=cfg.momentum, weight_decay=cfg.weight_decay)

max_acc = 0
task = ['PN', 'STR', 'PIG', 'RS', 'DaG', 'BWV', 'VS', 'DIAG']

best_avg_acc = 0
best_avg_combine_acc = 0
best_avg_acc_epoch = 0
best_avg_combine_acc_epoch = 0
scheduler = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=cfg.T_max, eta_min=5e-6)

for epoch in range(0, cfg.train_number_epochs):
    lr = adjust_learning_rate(optimizer, epoch)
    # scheduler.step()
    current_lr = 0
    for i, param_group in enumerate(optimizer.param_groups):
        current_lr = param_group['lr']
    train_loss_record = []

    for _, data in enumerate(train_loader, 0):

        net.train()
        img0, img1, label = data
        img0 = Variable(img0).cuda()
        img1 = Variable(img1).cuda()
        for i in range(0, len(label)):
            label[i] = Variable(torch.LongTensor(label[i])).cuda()
        optimizer.zero_grad()
        output_x, output_y, output_h, output_f = net(img0, img1)
        loss_x = criterion(output_x, label)
        loss_y = criterion(output_y, label)
        loss_h = criterion(output_h, label)
        loss_f = criterion(output_f, label)
        loss_all = loss_f
        # loss_all = loss_x + loss_y + loss_h + loss_f
        # if epoch >= 199:
        #     loss_all = loss_f
        loss_all.backward()
        optimizer.step()
        train_loss_record.append(loss_all.item())

    epoch_loss = np.mean(train_loss_record)
    print_and_write("\nEpoch {}/{}, LR {} Current train loss: {}".format(epoch + 1, cfg.train_number_epochs,
                                                               current_lr, epoch_loss))

    # print('start train_test ##########################################################')
    # acc, sen, spe, pre, auc, combine_acc, combine_sen, combine_spe, combine_pre, combine_auc = \
    #     test_model(image_datasets["train_test"])
    # print("acc", acc, "\nsen", sen, "\nspe", spe, "\npre", pre, "\nauc", auc,
    #       "\ncombine_acc", combine_acc, "\ncombine_sen", combine_sen, "\ncombine_spe",
    #       combine_spe, "\ncombine_pre", combine_pre, "\ncombine_auc", combine_auc)

    # print('start val ##########################################################')
    # acc, sen, spe, pre, auc, combine_acc, combine_sen, combine_spe, combine_pre, combine_auc = \
    #     test_model(image_datasets["val"])
    # print("acc", acc, "\nsen", sen, "\nspe", spe, "\npre", pre, "\nauc", auc,
    #       "\ncombine_acc", combine_acc, "\ncombine_sen", combine_sen, "\ncombine_spe",
    #       combine_spe, "\ncombine_pre", combine_pre, "\ncombine_auc", combine_auc)

    print_and_write('start test ##########################################################')
    avg_acc, avg_combine_acc, avg_acc_list, avg_combine_acc_list, \
    acc, sen, spe, pre, auc, combine_acc, combine_sen, combine_spe, combine_pre, combine_auc = \
        test_model(image_datasets["test"])
    # print("avg_acc", avg_acc, "\navg_combine_acc", avg_combine_acc,
    #       "\navg_acc_list", avg_acc_list, "\navg_combine_acc_list", avg_combine_acc_list,
    #       "\nacc", acc, "\nsen", sen, "\nspe", spe, "\npre", pre, "\nauc", auc,
    #       "\ncombine_acc", combine_acc, "\ncombine_sen", combine_sen, "\ncombine_spe", combine_spe,
    #       "\ncombine_pre", combine_pre, "\ncombine_auc", combine_auc)

    print_and_write("avg_acc {} \navg_combine_acc {} \navg_acc_list {} \navg_combine_acc_list {} "
          "\nacc {} \nsen {} \nspe {} \npre {} \nauc {}"
          "\ncombine_acc {} \ncombine_sen {} \ncombine_spe {} \ncombine_pre {} \ncombine_auc {}".format(avg_acc, avg_combine_acc, avg_acc_list, avg_combine_acc_list,
                                                                                                        acc, sen, spe, pre, auc,
                                                                                                        combine_acc, combine_sen, combine_spe, combine_pre, combine_auc))

    # 'PN', 'STR', 'PIG', 'RS', 'DaG', 'BWV', 'VS', 'DIAG'
    # BWV DaG PIG PN   RS   STR VS DIAG
    # PRS IR  IR  ATP  PRS  IR  IR MEL
    print_and_write("\tBWV \tDaG \tPIG \tPN \tRS \tSTR \tVS \tDIAG \tAvg")
    print_and_write("\tPRS \tIR  \tIR  \tATP \tPRS \tIR \tIR \tMEL")

    print_and_write("Sens")
    avg_sen = (sen[5][1] + sen[4][2] + sen[2][2] + sen[0][2] + sen[3][1] + sen[1][2] + sen[6][2] + sen[7][2])/8
    # print("\t{:.3f}".format(sen[5][1]),"{:.3f}".format(sen[4][2]),"{:.3f}".format(sen[2][2]),"{:.3f}".format(sen[0][2]),
    #       "{:.3f}".format(sen[3][1]),"{:.3f}".format(sen[1][2]),"{:.3f}".format(sen[6][2]),"{:.3f}".format(sen[7][2]),
    #       "{:.3f}".format(avg_sen))
    print_and_write("\t{:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f}".format(sen[5][1], sen[4][2], sen[2][2], sen[0][2],
                                                                                    sen[3][1], sen[1][2], sen[6][2], sen[7][2], avg_sen))

    print_and_write("Spec")
    avg_spe = (spe[5][1] + spe[4][2] + spe[2][2] + spe[0][2] + spe[3][1] + spe[1][2] + spe[6][2] + spe[7][2])/8
    # print("\t{:.3f}".format(spe[5][1]),"{:.3f}".format(spe[4][2]),"{:.3f}".format(spe[2][2]),"{:.3f}".format(spe[0][2]),
    #       "{:.3f}".format(spe[3][1]),"{:.3f}".format(spe[1][2]),"{:.3f}".format(spe[6][2]),"{:.3f}".format(spe[7][2]),
    #       "{:.3f}".format(avg_spe))
    print_and_write("\t{:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f}".format(spe[5][1], spe[4][2], spe[2][2], spe[0][2],
                                                                                              spe[3][1], spe[1][2], spe[6][2], spe[7][2], avg_spe))

    print_and_write("Prec")
    avg_pre = (pre[5][1] + pre[4][2] + pre[2][2] + pre[0][2] + pre[3][1] + pre[1][2] + pre[6][2] + pre[7][2])/8
    # print("\t{:.3f}".format(pre[5][1]),"{:.3f}".format(pre[4][2]),"{:.3f}".format(pre[2][2]),"{:.3f}".format(pre[0][2]),
    #       "{:.3f}".format(pre[3][1]),"{:.3f}".format(pre[1][2]),"{:.3f}".format(pre[6][2]),"{:.3f}".format(pre[7][2]),
    #       "{:.3f}".format(avg_pre))
    print_and_write("\t{:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f}".format(pre[5][1], pre[4][2], pre[2][2], pre[0][2],
                                                                                              pre[3][1], pre[1][2], pre[6][2], pre[7][2], avg_pre))

    print_and_write("Auroc")
    avg_auc = (auc[5][1] + auc[4][2] + auc[2][2] + auc[0][2] + acc[3][1] + auc[1][2] + auc[6][2] + auc[7][2])/8
    # print("\t{:.3f}".format(auc[5][1]),"{:.3f}".format(auc[4][2]),"{:.3f}".format(auc[2][2]),"{:.3f}".format(auc[0][2]),
    #       "{:.3f}".format(auc[3][1]),"{:.3f}".format(auc[1][2]),"{:.3f}".format(auc[6][2]),"{:.3f}".format(auc[7][2]),
    #       "{:.3f}".format(avg_auc))
    print_and_write("\t{:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f}".format(auc[5][1], auc[4][2], auc[2][2], auc[0][2],
                                                                                              auc[3][1], auc[1][2], auc[6][2], auc[7][2], avg_auc))

    print_and_write("combine_Sens")
    combine_avg_sen = (combine_sen[5][1] + combine_sen[4][2] + combine_sen[2][2] + combine_sen[0][2] +
                       combine_sen[3][1] + combine_sen[1][2] + combine_sen[6][2] + combine_sen[7][2])/8
    # print("\t{:.3f}".format(combine_sen[5][1]),"{:.3f}".format(combine_sen[4][2]),"{:.3f}".format(combine_sen[2][2]),
    #       "{:.3f}".format(combine_sen[0][2]),"{:.3f}".format(combine_sen[3][1]),"{:.3f}".format(combine_sen[1][2]),
    #       "{:.3f}".format(combine_sen[6][2]),"{:.3f}".format(combine_sen[7][2]),"{:.3f}".format(combine_avg_sen))
    print_and_write("\t{:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f}".format(combine_sen[5][1], combine_sen[4][2], combine_sen[2][2], combine_sen[0][2],
                                                                                              combine_sen[3][1], combine_sen[1][2], combine_sen[6][2], combine_sen[7][2],
                                                                                              combine_avg_sen))

    print_and_write("combine_Spec")
    combine_avg_spe = (combine_spe[5][1] + combine_spe[4][2] + combine_spe[2][2] + combine_spe[0][2] +
                       combine_spe[3][1] + combine_spe[1][2] + combine_spe[6][2] + combine_spe[7][2])/8
    # print("\t{:.3f}".format(combine_spe[5][1]),"{:.3f}".format(combine_spe[4][2]),"{:.3f}".format(combine_spe[2][2]),
    #       "{:.3f}".format(combine_spe[0][2]),"{:.3f}".format(combine_spe[3][1]),"{:.3f}".format(combine_spe[1][2]),
    #       "{:.3f}".format(combine_spe[6][2]),"{:.3f}".format(combine_spe[7][2]),"{:.3f}".format(combine_avg_spe))
    print_and_write("\t{:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f}".format(combine_spe[5][1], combine_spe[4][2], combine_spe[2][2], combine_spe[0][2],
                                                                                              combine_spe[3][1], combine_spe[1][2], combine_spe[6][2], combine_spe[7][2],
                                                                                              combine_avg_spe))

    print_and_write("combine_Prec")
    combine_avg_pre = (combine_pre[5][1] + combine_pre[4][2] + combine_pre[2][2] + combine_pre[0][2] +
                       combine_pre[3][1] + combine_pre[1][2] + combine_pre[6][2] + combine_pre[7][2])/8
    # print("\t{:.3f}".format(combine_pre[5][1]),"{:.3f}".format(combine_pre[4][2]),"{:.3f}".format(combine_pre[2][2]),
    #       "{:.3f}".format(combine_pre[0][2]),"{:.3f}".format(combine_pre[3][1]),"{:.3f}".format(combine_pre[1][2]),
    #       "{:.3f}".format(combine_pre[6][2]),"{:.3f}".format(combine_pre[7][2]),"{:.3f}".format(combine_avg_pre))
    print_and_write("\t{:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f}".format(combine_pre[5][1], combine_pre[4][2], combine_pre[2][2], combine_pre[0][2],
                                                                                              combine_pre[3][1], combine_pre[1][2], combine_pre[6][2], combine_pre[7][2],
                                                                                              combine_avg_pre))

    print_and_write("combine_Auroc")
    combine_avg_auc = (combine_auc[5][1] + combine_auc[4][2] + combine_auc[2][2] + combine_auc[0][2] +
                       combine_acc[3][1] + combine_auc[1][2] + combine_auc[6][2] + combine_auc[7][2])/8
    # print("\t{:.3f}".format(combine_auc[5][1]),"{:.3f}".format(combine_auc[4][2]),"{:.3f}".format(combine_auc[2][2]),
    #       "{:.3f}".format(combine_auc[0][2]),"{:.3f}".format(combine_auc[3][1]),"{:.3f}".format(combine_auc[1][2]),
    #       "{:.3f}".format(combine_auc[6][2]),"{:.3f}".format(combine_auc[7][2]),"{:.3f}".format(combine_avg_auc))
    print_and_write("\t{:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f}".format(combine_auc[5][1], combine_auc[4][2], combine_auc[2][2], combine_auc[0][2],
                                                                                              combine_auc[3][1], combine_auc[1][2], combine_auc[6][2], combine_auc[7][2],
                                                                                              combine_avg_auc))

    if avg_acc > best_avg_acc:
        best_avg_acc = avg_acc
        best_avg_acc_epoch = epoch + 1
    if avg_combine_acc > best_avg_combine_acc:
        best_avg_combine_acc = avg_combine_acc
        best_avg_combine_acc_epoch = epoch + 1
    print_and_write("Epoch %d/%d, current best_avg_acc is: %.6f obtained in epoch %d" % (epoch+1, cfg.train_number_epochs,
                                                                           best_avg_acc, best_avg_acc_epoch))
    print_and_write("Epoch %d/%d, current best_avg_combine_acc is: %.6f obtained in epoch %d" % (epoch+1, cfg.train_number_epochs,
                                                                        best_avg_combine_acc, best_avg_combine_acc_epoch))
print_and_write(cfg.save_file)

